package com.ymm.system.core.facade;

import com.ymm.system.api.dto.CargoPriceRequest;
import com.ymm.system.api.facade.SystemDefinePriceService;
import com.ymm.system.api.utils.CarTypeEnum;
import com.ymm.system.api.utils.Result;
import com.ymm.system.api.utils.ResultCodeEnum;
import com.ymm.system.core.config.BSGSPriceConfig;
import com.ymm.system.core.config.JSPriceConfig;
import com.ymm.system.core.utils.AddressUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;


/**
 * @Author zikang.yao
 * @Description TODO
 * @Date 2022/8/3 14:02
 * @Version 1.0
 */
@Service(version = "server")
@Component
@Slf4j
public class SystemDefinePriceServiceImpl implements SystemDefinePriceService {

    List<String> jsCity=new ArrayList<String>(){{
        add("南京市");
        add("无锡市");
        add("镇江市");
        add("常州市");
        add("苏州市");
    }};
    List<String> bsgsCity=new ArrayList<String>(){{
        add("北京市");
        add("上海市");
        add("广州市");
        add("深圳市");
    }};
    public static HashMap<Integer, List<Double>> jsmap = new HashMap<Integer, List<Double>>() {{
        put(CarTypeEnum.SMALL_VAN.getCode().intValue(), new ArrayList<Double>() {{
            add(JSPriceConfig.getPRICE_START_SMALLVAN());
            add(JSPriceConfig.getDISTANCE_START_SMCAR());
            add(JSPriceConfig.getUNITPRICE_SMALLVAN());
        }});
        put(CarTypeEnum.SMALL_FLAT.getCode(), new ArrayList<Double>() {{
            add(JSPriceConfig.getPRICE_START_SMALLFLAT());
            add(JSPriceConfig.getDISTANCE_START_SMCAR());
            add(JSPriceConfig.getUNITPRICE_SMALLFLAT());
        }});
        put(CarTypeEnum.SMALL_TRUNK.getCode(), new ArrayList<Double>() {{
            add(JSPriceConfig.getPRICE_START_SMALLTRUNK());
            add(JSPriceConfig.getDISTANCE_START_SMCAR());
            add(JSPriceConfig.getUNITPRICE_SMALLTRUNK());
        }});
        put(CarTypeEnum.MEDIUM_VAN.getCode().intValue(), new ArrayList<Double>() {{
            add(JSPriceConfig.getPRICE_START_MEDIUNVAN());
            add(JSPriceConfig.getDISTANCE_START_SMCAR());
            add(JSPriceConfig.getUNITPRICE_MEDIUMVAN());
        }});
        put(CarTypeEnum.MEDIUM_TRUNK.getCode(), new ArrayList<Double>() {{
            add(JSPriceConfig.getPRICE_START_MEDIUNTRUNK());
            add(JSPriceConfig.getDISTANCE_START_SMCAR());
            add(JSPriceConfig.getUNITPRICE_MEDIUMTRUNK());
        }});
        put(CarTypeEnum.LARGE_6_8.getCode(), new ArrayList<Double>() {{
            add(JSPriceConfig.getPRICE_START_6_8());
            add(JSPriceConfig.getDISTANCE_START_LCAR());
            add(JSPriceConfig.getUNITPRICE_6_8());
        }});
        put(CarTypeEnum.LARGE_7_6.getCode(), new ArrayList<Double>() {{
            add(JSPriceConfig.getPRICE_START_7_6());
            add(JSPriceConfig.getDISTANCE_START_LCAR());
            add(JSPriceConfig.getUNITPRICE_7_6());
        }});
        put(CarTypeEnum.LARGE_9_6.getCode(), new ArrayList<Double>() {{
            add(JSPriceConfig.getPRICE_START_9_6());
            add(JSPriceConfig.getDISTANCE_START_LCAR());
            add(JSPriceConfig.getPRICE_START_9_6());
        }});
    }};

    public static HashMap<Integer, List<Double>> bsgsmap = new HashMap<Integer, List<Double>>() {{
        put(CarTypeEnum.SMALL_VAN.getCode().intValue(), new ArrayList<Double>() {{
            add(BSGSPriceConfig.getPRICE_START_SMALLVAN());
            add(BSGSPriceConfig.getDISTANCE_START_SMCAR());
            add(BSGSPriceConfig.getUNITPRICE_SMALLVAN());
        }});
        put(CarTypeEnum.SMALL_FLAT.getCode(), new ArrayList<Double>() {{
            add(BSGSPriceConfig.getPRICE_START_SMALLFLAT());
            add(BSGSPriceConfig.getDISTANCE_START_SMCAR());
            add(BSGSPriceConfig.getUNITPRICE_SMALLFLAT());
        }});
        put(CarTypeEnum.SMALL_TRUNK.getCode(), new ArrayList<Double>() {{
            add(BSGSPriceConfig.getPRICE_START_SMALLTRUNK());
            add(BSGSPriceConfig.getDISTANCE_START_SMCAR());
            add(BSGSPriceConfig.getUNITPRICE_SMALLTRUNK());
        }});
        put(CarTypeEnum.MEDIUM_VAN.getCode().intValue(), new ArrayList<Double>() {{
            add(BSGSPriceConfig.getPRICE_START_MEDIUNVAN());
            add(BSGSPriceConfig.getDISTANCE_START_SMCAR());
            add(BSGSPriceConfig.getUNITPRICE_MEDIUMVAN());
        }});
        put(CarTypeEnum.MEDIUM_TRUNK.getCode(), new ArrayList<Double>() {{
            add(BSGSPriceConfig.getPRICE_START_MEDIUNTRUNK());
            add(BSGSPriceConfig.getDISTANCE_START_SMCAR());
            add(BSGSPriceConfig.getUNITPRICE_MEDIUMTRUNK());
        }});
        put(CarTypeEnum.LARGE_6_8.getCode(), new ArrayList<Double>() {{
            add(BSGSPriceConfig.getPRICE_START_6_8());
            add(BSGSPriceConfig.getDISTANCE_START_LCAR());
            add(BSGSPriceConfig.getUNITPRICE_6_8());
        }});
        put(CarTypeEnum.LARGE_7_6.getCode(), new ArrayList<Double>() {{
            add(BSGSPriceConfig.getPRICE_START_7_6());
            add(BSGSPriceConfig.getDISTANCE_START_LCAR());
            add(BSGSPriceConfig.getUNITPRICE_7_6());
        }});
        put(CarTypeEnum.LARGE_9_6.getCode(), new ArrayList<Double>() {{
            add(BSGSPriceConfig.getPRICE_START_9_6());
            add(BSGSPriceConfig.getDISTANCE_START_LCAR());
            add(BSGSPriceConfig.getPRICE_START_9_6());
        }});
    }};

    public static HashMap<String,Boolean> holidayMap=new HashMap<String,Boolean>(){{
        put("2022-01-01",true);put("2022-01-02",true);put("2022-01-03",true);
        put("2022-01-30",true);put("2022-01-31",true);put("2022-02-01",true);put("2022-02-02",true);put("2022-02-03",true);put("2022-02-04",true);put("2022-02-05",true);put("2022-02-06",true);
        put("2022-04-03",true);put("2022-04-04",true);put("2022-04-05",true);
        put("2022-04-30",true);put("2022-05-01",true);put("2022-05-02",true);put("2022-05-03",true);put("2022-05-04",true);put("2022-05-05",true);
        put("2022-06-03",true);put("2022-06-04",true);put("2022-06-05",true);
        put("2022-09-10",true);put("2022-09-11",true);put("2022-09-12",true);
        put("2022-10-01",true);put("2022-10-02",true);put("2022-10-03",true);put("2022-10-04",true);put("2022-10-05",true);put("2022-10-06",true);put("2022-10-07",true);
    }};


        
    @Override
    public Result<Integer> definePrice(CargoPriceRequest cargoPriceRequest) {
        Result<Integer> cargoPriceRequestParametersCheckResult = cargoPriceRequestParametersCheck(cargoPriceRequest);
        if (cargoPriceRequestParametersCheckResult == null) {
            return Result.fail(null);
        }
        if (!cargoPriceRequestParametersCheckResult.isSuccess()) {
            return cargoPriceRequestParametersCheckResult;
        }
        Integer additionPay=0;
        String cargoDateMon;
        String cargoDateDay;
        Double startPrice;
        Double startDistance;
        Double outierPrice;
        BigDecimal cargoSrcLat = cargoPriceRequest.getCargoSrcLat();
        BigDecimal cargoSrcLon = cargoPriceRequest.getCargoSrcLon();
        BigDecimal cargoDesLat = cargoPriceRequest.getCargoDesLat();
        BigDecimal cargoDesLon = cargoPriceRequest.getCargoDesLon();
        Integer cargoRequireType = cargoPriceRequest.getCargoRequireType();
        Date cargoDeliveryTime = cargoPriceRequest.getCargoDeliveryTime();
        String city = cargoPriceRequest.getCity();
        System.out.println(cargoDeliveryTime);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
        String cargoDate = simpleDateFormat.format(cargoDeliveryTime);
        log.info(cargoDate);
//        String cargoDateY=Integer.parseInt(cargoDate.substring(0,4))-1900+"";
        String cargoDateY=Integer.parseInt(cargoDate.substring(0,4))+"";
//        if(cargoDate.substring(5,7).startsWith("0")|| cargoDate.startsWith("10", 5)){
//            cargoDateMon="0"+(Integer.parseInt(cargoDate.substring(5,7))-1);
//        }else{
//            cargoDateMon=Integer.parseInt(cargoDate.substring(5,7))-1+"";
//        }
        if(cargoDate.substring(5,7).startsWith("0")){
            cargoDateMon="0"+(Integer.parseInt(cargoDate.substring(5,7)));
        }else{
            cargoDateMon=Integer.parseInt(cargoDate.substring(5,7))+"";
        }
        if(cargoDate.substring(8,10).startsWith("0")){
            cargoDateDay="0"+(Integer.parseInt(cargoDate.substring(8,10)));
        }else{
            cargoDateDay=Integer.parseInt(cargoDate.substring(8,10))+"";
        }
        String isHoliday=cargoDateY+"-"+cargoDateMon+"-"+cargoDateDay;
        log.info(isHoliday);
        System.out.println(isHoliday);
        if(holidayMap.containsKey(isHoliday)){
            additionPay=3000;
        }
        log.info(additionPay+"");
        int cargoDateH = Integer.parseInt(cargoDate.substring(11, 13));
        Double timeFactor = timeZone(cargoDateH,city);
        if(jsCity.contains(city)){
            List<Double> priceInfo = jsmap.get(cargoRequireType);
            startPrice = priceInfo.get(0);
            startDistance = priceInfo.get(1);
            outierPrice = priceInfo.get(2);
        }else{
            List<Double> priceInfo = bsgsmap.get(cargoRequireType);
            startPrice = priceInfo.get(0);
            startDistance = priceInfo.get(1);
            outierPrice = priceInfo.get(2);
        }
        //实际订单距离
        double actualDistance = algorithm(cargoSrcLon.doubleValue(), cargoSrcLat.doubleValue(),
                cargoDesLon.doubleValue(), cargoDesLat.doubleValue())/1000;
        if(actualDistance <= startDistance){
            return Result.success((int) (timeFactor * startPrice * 100)+additionPay);
        } else {
            return Result.success((int) (timeFactor * (startPrice + outierPrice * (actualDistance - startDistance))*100)+additionPay);
        }
    }

    public Double timeZone(int i,String city) {
        if(jsCity.contains(city)){
            if (i >= 3 && i <= 8) {
                return JSPriceConfig.getTIME_MORNING_FACTOR();
            } else if (i >= 12 && i <= 14) {
                return JSPriceConfig.getTIME_NOON_FACTOR();
            } else if (i >= 18 && i <= 22) {
                return JSPriceConfig.getTIME_NIGHT_FACTOR();
            } else {
                return JSPriceConfig.getTIME_NORMAL_FACTOR();
            }
        }else{
            if (i >= 3 && i <= 8) {
                return BSGSPriceConfig.getTIME_MORNING_FACTOR();
            } else if (i >= 12 && i <= 14) {
                return BSGSPriceConfig.getTIME_NOON_FACTOR();
            } else if (i >= 18 && i <= 22) {
                return BSGSPriceConfig.getTIME_NIGHT_FACTOR();
            } else {
                return BSGSPriceConfig.getTIME_NORMAL_FACTOR();
            }
        }

    }

    //计算经纬度距离
    public double algorithm(double longitude1, double latitude1, double longitude2, double latitude2) {
        double Lat1 = rad(latitude1); // 纬度

        double Lat2 = rad(latitude2);

        double a = Lat1 - Lat2;//两点纬度之差

        double b = rad(longitude1) - rad(longitude2); //经度之差

        double s = 2 * Math.asin(Math

                .sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(Lat1) * Math.cos(Lat2) * Math.pow(Math.sin(b / 2), 2)));//计算两点距离的公式

        s = s * 6378137.0;//弧长乘地球半径（半径为米）

        s = Math.round(s * 10000) / 10000;//精确距离的数值

        return s;

    }

    //角度换成弧度
    private static double rad(double d) {
        return d * Math.PI / 180.00;
    }

    /**
     * 定价请求参数校验
     *
     * @param cargoPriceRequest 定价请求
     * @return 结果
     */
    private Result<Integer> cargoPriceRequestParametersCheck(CargoPriceRequest cargoPriceRequest) {
        if (cargoPriceRequest == null || cargoPriceRequest.getCargoDeliveryTime() == null) {
            return Result.fail(null, ResultCodeEnum.PARAM_ERROR.getCode(), "参数为空");
        }
        if (!AddressUtils.latLongCheck(cargoPriceRequest.getCargoSrcLat(), cargoPriceRequest.getCargoSrcLon())) {
            return Result.fail(null, ResultCodeEnum.PARAM_ERROR.getCode(), "装货地位置错误！");
        }
        if (!AddressUtils.latLongCheck(cargoPriceRequest.getCargoDesLat(), cargoPriceRequest.getCargoDesLon())) {
            return Result.fail(null, ResultCodeEnum.PARAM_ERROR.getCode(), "目的地位置错误！");
        }
        if (!cargoRequireTypeCheck(cargoPriceRequest.getCargoRequireType())) {
            return Result.fail(null, ResultCodeEnum.PARAM_ERROR.getCode(), "所需车类型参数错误！");
        }
        if (!cityCheck(cargoPriceRequest.getCity())) {
            return Result.fail(null, ResultCodeEnum.PARAM_ERROR.getCode(), "暂不支持该城市！");
        }
        return Result.success(null);
    }

    /**
     * 所需车辆类型校验
     *
     * @param cargoRequireType 所需车辆类型（Integer）
     * @return 结果
     */
    private boolean cargoRequireTypeCheck(Integer cargoRequireType) {
        return cargoRequireType >= 1 && cargoRequireType <= 9;
    }

    /**
     * 城市校验
     */
    public boolean cityCheck(String city){
        List<String> supportCity=new ArrayList<String>(){{
            add("北京市");add("上海市");add("广州市");add("深圳市");
            add("南京市");add("镇江市");add("苏州市");add("无锡市");add("常州市");
        }};
        return supportCity.contains(city);
    }
}

